/*
 * Camera.cpp
 *
 *  Created on: 2018年3月19日
 *      Author: zhengboyuan
 */

#include "Camera.h"
#include <algorithm>

#ifndef     SAFE_RELEASE
#define     SAFE_RELEASE(p)          if((p) != NULL) {p->Release();}
#endif

#pragma comment(lib, "strmiids.lib")


static std::string toAnsi(const std::wstring& wstr)
{
	int unicodeLen = wcslen(wstr.c_str());
	int length = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), unicodeLen, NULL, 0, NULL, NULL);
	char* buffer = new char[length + 1];
	memset(buffer, 0, length + 1);
	WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), unicodeLen, buffer, length, NULL, NULL);
	std::string str(buffer);
	delete[] buffer;
	return str;
}



Camera::Camera()
{
}

Camera::~Camera()
{
}

int Camera::listDevice(DeviceList& deviceList)
{
	int count = 0;
	WStringArray arrName;
	HRESULT hr = enumSystemDevice(CLSID_VideoInputDeviceCategory, arrName);
	for (size_t i = 0; i < arrName.size(); ++ i)
	{
		WStringArray::iterator itBegin = arrName.begin();
		WStringArray::iterator itNow = itBegin;
		std::advance(itNow, i);

		size_t idx = std::count(itBegin, itNow, arrName[i]);

		Device device;
		device.index = idx;
		device.name = toAnsi(arrName[i]);

		deviceList.push_back(device);

		count ++;
	}
	return count;
}


HRESULT Camera::getFriendlyName(IMoniker* pMoniker, VARIANT& var)
{
    IPropertyBag*  iBag = NULL;
	HRESULT hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&iBag);
	if (SUCCEEDED(hr))
	{
	    var.vt = VT_BSTR;
	    hr = iBag->Read(L"FriendlyName", &var, NULL);

        SAFE_RELEASE(iBag);
	}
    return hr;
}

HRESULT Camera::getFriendlyName(IMoniker* pMoniker, WString& wstr)
{
    VARIANT var;
    HRESULT hr = getFriendlyName(pMoniker, var);
    if (SUCCEEDED(hr))
    {
        wstr.assign(var.bstrVal);
        SysFreeString(var.bstrVal);
    }
    return hr;
}

IEnumMoniker* getClassEnumerator(REFCLSID clsidDeviceClass)
{
    IEnumMoniker*	iEmMoniker = NULL;

    ICreateDevEnum* iCreateDevEnum = NULL;
	CoCreateInstance(CLSID_SystemDeviceEnum,
		NULL, CLSCTX_INPROC_SERVER,	IID_ICreateDevEnum,
		(void**)&iCreateDevEnum);

    if (iCreateDevEnum)
    {
        iCreateDevEnum->CreateClassEnumerator(clsidDeviceClass, &iEmMoniker, 0 );
        iCreateDevEnum->Release();
    }
    return iEmMoniker;
}


HRESULT Camera::enumSystemDevice(REFCLSID clsidDeviceClass, WStringArray& array )
{
	IEnumMoniker*	iEmMoniker = getClassEnumerator(clsidDeviceClass);
    if (!iEmMoniker)
    {
        return E_FAIL;
    }

	iEmMoniker->Reset();
	IMoniker* pMoniker = NULL;
	ULONG cFetched = 0;
	while( true )
	{
		HRESULT hr = iEmMoniker->Next(1, &pMoniker, &cFetched);
		if (hr != S_OK )
		{
			break;
		}

        WString wstr;
        hr = getFriendlyName(pMoniker, wstr);
        if (SUCCEEDED(hr))
		{
            array.push_back(wstr);
        }

		SAFE_RELEASE(pMoniker);
	}

    SAFE_RELEASE(iEmMoniker);

	return S_OK;
}
